/*
 * Copyright (c) 2020 Nanjing Xiaoxiongpai Intelligent Technology Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 康复训练手套
 * 功能： 给需要进行手部训练的患者提供服务，可设置三档训练强度
 * dayu200可实时控制启停，查看训练次数 
 * Data: 2022.09.02
 * Auther: HelloKun & luoChao
 */

#include <stdio.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

#include "lwip/sockets.h"
#include "wifi_connect.h"
#include "wifiiot_errno.h"
#include "wifiiot_pwm.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "hi_io.h"
#include "hi_time.h"

#define _PROT_ 8888
#define TCP_BACKLOG 10

//在sock_fd 进行监听，在 new_fd 接收新的链接
int sock_fd, new_fd;

char recvbuf[512];
char *buf = "Training Start";
char *buf2 = "Training OK";
typedef enum
{
	LEV0 = '0',
	LEV1,
	LEV2,
	LEV3,
} get_dayu_cmd;

#define TRAIN_LEV0 0
#define TRAIN_LEV1 38000
#define TRAIN_LEV2 49000
#define TRAIN_LEV3 40000
#define TRAIN_TIME0 0
#define TRAIN_TIME1 3
#define TRAIN_TIME2 5
#define TRAIN_TIME3 8 // 训练强度 经验参数
#define PWM_SEQ 40000 // PWM 频率

struct FINGER
{
	int lev;
	int TrainingTims;
};
struct FINGER fingerTraining;

void IO_INIT(void)
{
	GpioInit();
	// 气泵
	IoSetFunc(WIFI_IOT_IO_NAME_GPIO_9, WIFI_IOT_IO_FUNC_GPIO_9_PWM0_OUT);
	GpioSetDir(WIFI_IOT_IO_NAME_GPIO_9, WIFI_IOT_GPIO_DIR_OUT);
	PwmInit(WIFI_IOT_PWM_PORT_PWM0);
	// 气阀
	IoSetFunc(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_IO_FUNC_GPIO_11_GPIO);
	GpioSetDir(WIFI_IOT_IO_NAME_GPIO_11, WIFI_IOT_GPIO_DIR_OUT);
	GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0);
}

// 加压-泄气-加压-泄气 循环
void CTR_Device(void)
{
	GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0);
	while (fingerTraining.TrainingTims--)
	{
		PwmStart(WIFI_IOT_PWM_PORT_PWM0, fingerTraining.lev, PWM_SEQ);
		sleep(2);
		GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 1); // 泄气
		sleep(1);
		GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0); // 通气
	}
	GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_11, 0);
	PwmStop(WIFI_IOT_PWM_PORT_PWM0);		   // 气泵停止
	fingerTraining.TrainingTims = TRAIN_TIME0; // 计数归零
}

static void TCPServerTask(void)
{
	IO_INIT();

	// 服务端地址信息
	struct sockaddr_in server_sock;

	// 客户端地址信息
	struct sockaddr_in client_sock;
	int sin_size;

	struct sockaddr_in *cli_addr;

	// 连接Wifi
	WifiConnect("r1", "88888889");

	// 创建socket
	if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket is error\r\n");
		exit(1);
	}

	bzero(&server_sock, sizeof(server_sock));
	server_sock.sin_family = AF_INET;
	server_sock.sin_addr.s_addr = htonl(INADDR_ANY);
	server_sock.sin_port = htons(_PROT_);

	// 调用bind函数绑定socket和地址
	if (bind(sock_fd, (struct sockaddr *)&server_sock, sizeof(struct sockaddr)) == -1)
	{
		perror("bind is error\r\n");
		exit(1);
	}

	// 调用listen函数监听(指定port监听)
	if (listen(sock_fd, TCP_BACKLOG) == -1)
	{
		perror("listen is error\r\n");
		exit(1);
	}

	printf("start accept\n");

	// 调用accept函数从队列中
	while (1)
	{
		sin_size = sizeof(struct sockaddr_in);

		if ((new_fd = accept(sock_fd, (struct sockaddr *)&client_sock, (socklen_t *)&sin_size)) == -1)
		{
			perror("accept");
			continue;
		}

		cli_addr = malloc(sizeof(struct sockaddr));

		printf("accept addr\r\n");

		if (cli_addr != NULL)
		{
			memcpy(cli_addr, &client_sock, sizeof(struct sockaddr));
		}

		// 处理目标
		ssize_t ret;

		while (1)
		{
			if ((ret = recv(new_fd, recvbuf, sizeof(recvbuf), 0)) == -1)
			{
				printf("recv error \r\n");
			}
			printf("recv :%s\r\n", recvbuf);
			switch (recvbuf[0])
			{
			case LEV0:
			{
				fingerTraining.TrainingTims = TRAIN_TIME0;
				fingerTraining.lev = TRAIN_LEV0;
				break;
			}
			case LEV1:
			{
				fingerTraining.TrainingTims = TRAIN_TIME1;
				fingerTraining.lev = TRAIN_LEV1;
				break;
			}
			case LEV2:
			{
				fingerTraining.TrainingTims = TRAIN_TIME2;
				fingerTraining.lev = TRAIN_LEV2;
				break;
			}
			case LEV3:
			{
				fingerTraining.TrainingTims = TRAIN_TIME3;
				fingerTraining.lev = TRAIN_LEV3;
				break;
			}
			default:
				fingerTraining.TrainingTims = TRAIN_TIME0;
				fingerTraining.lev = TRAIN_LEV0;
				break;
			}
			if ((ret = send(new_fd, buf, strlen(buf) + 1, 0)) == -1)
			{
				perror("Send Start Failed : ");
			}
			CTR_Device();
			PwmStop(WIFI_IOT_PWM_PORT_PWM0); // 气泵停止
			if ((ret = send(new_fd, buf2, strlen(buf2) + 1, 0)) == -1)
			{
				perror("Send OK Failed : ");
			}
		}

		close(new_fd);
	}
}

static void TCPServerDemo(void)
{
	osThreadAttr_t attr;

	attr.name = "TCPServerTask";
	attr.attr_bits = 0U;
	attr.cb_mem = NULL;
	attr.cb_size = 0U;
	attr.stack_mem = NULL;
	attr.stack_size = 10240;
	attr.priority = osPriorityNormal;

	if (osThreadNew((osThreadFunc_t)TCPServerTask, NULL, &attr) == NULL)
	{
		printf("[TCPServerDemo] Falied to create TCPServerTask!\n");
	}
}

APP_FEATURE_INIT(TCPServerDemo);
